/*
 * Copyright:  2018 smarabbit studio.
 *
 *  Licensed under the Confluent Community License; you may not use this file
 *  except in compliance with the License.  You may obtain a copy of the License at
 *
 *  http://www.confluent.io/confluent-community-license
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OF ANY KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations under the License.
 *
 *  @作   者： 黄开晖 (117227773@qq.com)
 *  @日   期:  2021年5月28日
 */
package com.massyframework.beanskin.runtime.modular;

import java.nio.file.Path;
import java.util.Objects;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.massyframework.beanskin.Module;
import com.massyframework.beanskin.ModuleConfig;
import com.massyframework.beanskin.ModuleIdentifier;
import com.massyframework.beanskin.ModuleListener;
import com.massyframework.beanskin.ModuleRepository;
import com.massyframework.beanskin.license.License;
import com.massyframework.beanskin.service.ServiceRepository;
import com.massyframework.beanskin.util.classloading.ModuleClassLoader;
import com.massyframework.beanskin.util.localstore.LocalStore;
import com.massyframework.beanskin.util.version.Version;

/**
 * 抽象的模块
 * @author huangkh
 *
 */
public abstract class AbstractModule<C extends ModuleConfig> implements Module<C> {
	
	private final int id;
	private final Logger logger;
	private final C config;
	private final ModuleRepository moduleRepository;
	private final ServiceRepository serviceRepository;
	protected ModuleClassLoader moduleClassLoader;
	private License license;
	

	/**
	 * 构造方法
	 */
	public AbstractModule(AbstractModuleBuilder builder) {
		this.logger = LoggerFactory.getLogger("Module[".concat(builder.identifier.toIdentifier()).concat("]"));
		
		this.id = builder.id;
		this.moduleRepository = Objects.requireNonNull(builder.moduleRepository, "\"moduleRepository\" cannot be null.");
		this.moduleClassLoader = Objects.requireNonNull(builder.classLoader, "\"classLoader\" cannot be null.");
		this.config= this.createConfig(builder);
		this.serviceRepository = Objects.requireNonNull(builder.serviceRepositoryFactory, "\"serviceRepositoryFactory\" cannot be null.")
			.getServiceRepository(this);
		this.license = null;
	}
		
	/**
	 * 创建模块配置
	 * @param builder {@link AbstractModuleBuilder}
	 * @return {@link C}
	 */
	protected abstract C createConfig(AbstractModuleBuilder builder);
	
	/**
	 * 初始化
	 */
	public final void init() {
		this.doInit();
	}
	
	/**
	 * 初始化
	 */
	protected void doInit() {
	}
		
	/**
	 * 释放
	 */
	public void destory() {
		
	}
	
	@Override
	public <A> A adapt(Class<A> adaptType) {
		if (adaptType == ServiceRepository.class) {
			return adaptType.cast(this.serviceRepository);
		}
		return null;
	}

	@Override
	public ModuleClassLoader getModuleClassLoader() {
		return this.moduleClassLoader;
	}

	@Override
	public String getGroupId() {
		return this.getConfig().getGroupId();
	}

	@Override
	public String getModuleId() {
		return this.getConfig().getModuleId();
	}

	@Override
	public Version getVersion() {
		return this.getConfig().getVersion();
	}
	
	@Override
	public License getLicense() {
		return this.license;
	}

	@Override
	public int compareTo(ModuleIdentifier o) {
		return this.getConfig().compareTo(o);
	}

	@Override
	public void addListener(ModuleListener listener) {
		this.moduleRepository.addListener(listener);
	}

	@Override
	public int getId() {
		return this.id;
	}
	
	@Override
	public C getConfig() {
		return this.config;
	}
		
	@Override
	public Path getDataFile(String name) {
		ServiceRepository repo = ServiceRepository.retrieveFrom(this);
		LocalStore localStore = repo.getService(LocalStore.class);
		return localStore.getRuntimeDirectory(this.config);
	}

	
	@Override
	public Logger getLogger() {
		return this.logger;
	}
	
	@Override
	public boolean isModuleIdentifier(ModuleIdentifier identifier) {
		if (identifier == null) return false;
		return (this.getGroupId().equals(identifier.getGroupId())) &&
				(this.getModuleId().equals(identifier.getModuleId())) &&
				(this.getVersion().equals(identifier.getVersion()));
	}

	@Override
	public void removeListener(ModuleListener listener) {
		this.moduleRepository.removeListener(listener);
	}
	
	/**
	 * 比较并替换许可
	 * <p>
	 * 按有效期截止日比较，取截止日更大的许可做为最新的许可。
	 * @param value {@link License}
	 * @return {@link boolean}
	 */
	protected boolean comparisonAndReplace(License value) {
		if (value == null) {
			boolean result = this.license != null;
			this.license = null;
			return result;
		}
		
		if (this.license == null) {
			this.license = value;
			return true;
		}else {
			int order = this.license.compareTo(value);
			if (order>0) {
				this.license = value;
				return true;
			}
		}
		
		return false;
	}
	
	/**
	 * 模块资源库
	 * @return {@link ModuleRepository}
	 */
	protected ModuleRepository getModuleRepository() {
		return this.moduleRepository;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((config == null) ? 0 : config.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		AbstractModule<?> other = (AbstractModule<?>) obj;
		if (config == null) {
			if (other.config != null)
				return false;
		} else if (!config.equals(other.config))
			return false;
		return true;
	}

	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append(this.getClass().getSimpleName())
			.append(" [")
				.append(this.toIdentifier())
				.append("]");
		return builder.toString();
	}
	
}
